//#include "../Misc/part3_shared.h"
//
//int main(int argc, char **argv) {
//
//	DEHT *ht;
//	char** lexicon;
//	LONG_INDEX_PROJ lexicon_size = 0;
//	RULE rule;
//	int status;
//	LONG_INDEX_PROJ *seeds = NULL;
//	INI_PARAMS ini_params;
//	LONG_INDEX_PROJ num_of_chains;
//	LONG_INDEX_PROJ k = 0;
//	/* check size */
//	char firstPass[MAX_PASSWORD_LENGTH];
//	char newPass[MAX_PASSWORD_LENGTH];
//	BasicHashFunctionPtr crypt_func;
//	int func_buffer_length;
//	int cryptHashSize;
//	unsigned char curHash[MAX_BINARY_HASH];
//	/*char *curHexaHash; */
//
//	char input[MAX_INTPUT_SIZE + 1];
//	int quit = 0;
//
//	unsigned char target_key[MAX_BINARY_HASH];
//	char hexa_target_key[MAX_HASH_SIZE];
//	
//	char NewPassword[MAX_INTPUT_SIZE];
//	int NewPassword_length;
//	
//	int multi_length;
//	unsigned char multi_data[MAX_PASSWORD_LENGTH*MAX_RETURN_PW + 1];
//	unsigned char *multi_point[MAX_RETURN_PW + 1];
//	int i,j,w;
//	int found = 0;
//
//	FILE *bigfp = NULL;
//	char hexa_hash[MAX_HASH_SIZE*2 + 1];
//	char *big_name = "chains.txt";
//	int stat = 0;
//	FILE *fp;
//	
//	if (argc != 2)
//	{
//		fprintf(stderr, "Error: test_part3 <preferences filename>\n");
//		exit(1);
//	}
//
//	fp = fopen("wrong_pass.txt","w");
//
//	bigfp = fopen(big_name, "w");
//	if (!bigfp) {
//		exit(1);
//	}
//
//	/* load .ini file to struct */
//	ini_params = get_params_from_INI_file(argv[1]);
//	/* check params */
//	if (!strcmp(ini_params.HashFunction, "MD5")) {
//		crypt_func = MD5BasicHash;
//		func_buffer_length = MD5_OUTPUT_LENGTH_IN_BYTES;
//	} else if (!strcmp(ini_params.HashFunction, "SHA1")) {
//		crypt_func = SHA1BasicHash;
//		func_buffer_length = SHA1_OUTPUT_LENGTH_IN_BYTES;
//	} else {
//		fprintf(stderr, "Error: Hash %s is not supported\n", argv[1]);
//		exit(1);
//	}
//
//	if (ini_params.ChainLength < 1) {
//		fprintf(stderr, "Error: rainbow_chain_length in %s is %d. It should be positive number\n",
//				argv[1], ini_params.ChainLength);
//		exit(1);
//	}
//
//	if (ini_params.NumOfHashEntries < 1) {
//		fprintf(stderr, "Error: entries_in_hash_table in %s is %d. It should be a positive number\n",
//				argv[1], ini_params.NumOfHashEntries);
//		exit(1);
//	}
//
//	if (ini_params.ElementsInBucket < 1) {
//		fprintf(stderr, "Error: bucket_block_length in %s is %d. It should be a positive number\n",
//				argv[1], ini_params.ElementsInBucket);
//		exit(1);
//	}
//
// 	lexicon = load_lexicon(ini_params.LexiconName, &lexicon_size);
//	status = create_rule(&rule, ini_params.Rule, lexicon, lexicon_size);
//	if (status == -1) {
//		free_lexicon(lexicon, lexicon_size);
//		exit(1);
//	} 
//
//	/* create seed and DEHT */
//	ht = create_empty_DEHT(ini_params.OutputFilePrefix,cryptHashToTable,cryptHashTo64bit,ini_params.HashFunction,ini_params.NumOfHashEntries,
//						   ini_params.ElementsInBucket,BYTES_PER_VALIDATION_KEY);	
//	if (ht == NULL)
//	{
//		free_lexicon(lexicon, lexicon_size);
//		free_rule(&rule);
//		exit(1);
//	}
//	
//	status = calc_DEHT_last_block_per_bucket(ht);
//	if (status == DEHT_STATUS_FAIL){
//		lock_DEHT_files(ht);
//		free_lexicon(lexicon, lexicon_size);
//		free_rule(&rule);
//		exit(1);
//	}
//
//	seeds = (LONG_INDEX_PROJ*) malloc( ini_params.ChainLength * sizeof(LONG_INDEX_PROJ));
//	if (seeds == NULL){
//		fprintf(stderr, "Error: not enough memory\n");
//		lock_DEHT_files(ht);
//		free_lexicon(lexicon, lexicon_size);
//		free_rule(&rule);
//		exit(1);
//	}
//
//	for (i = 0 ; i < ini_params.ChainLength;  i++){
//		seeds[i] = pseudo_random_function((unsigned char *)ini_params.MainRandSeed, strlen(ini_params.MainRandSeed), i); 
//	}
//
//	status = write_DEHT_Seed(ht, seeds, ini_params.ChainLength);
//	if (status == DEHT_STATUS_FAIL)
//	{
//		free(seeds);
//		lock_DEHT_files(ht);
//		free_lexicon(lexicon, lexicon_size);
//		free_rule(&rule);
//		exit(1);
//	}
//
//	/* create chains and add to deht */
//	num_of_chains = (rule.number_of_possible_passwords * 10 ) / ini_params.ChainLength;
//	
//	
//	for (i = 0; i < num_of_chains; i ++)
//	{
//		k = pseudo_random_function((unsigned char*)ini_params.MainRandSeed, strlen(ini_params.MainRandSeed), i) % rule.number_of_possible_passwords;
//		generate_kth_password(k, firstPass, rule);
//		cryptHash(crypt_func, firstPass, (unsigned char*)curHash);
//
//		binary2hexa((unsigned char *)curHash, 16, hexa_hash, MAX_HASH_SIZE*2 + 1);
//		fprintf(bigfp, "%s - %s\t",firstPass,hexa_hash);
//		
//		for (j = 0; j < ini_params.ChainLength; j++)
//		{
//			k = pseudo_random_function((unsigned char*)curHash, func_buffer_length, seeds[j]) % rule.number_of_possible_passwords;
//			generate_kth_password(k, newPass, rule);
//			
//			cryptHash(crypt_func, newPass, (unsigned char*)curHash );
//
//		
//			binary2hexa((unsigned char *)curHash, 16, hexa_hash, MAX_HASH_SIZE*2 + 1);
//			fprintf(bigfp, "%s - %s\t",newPass,hexa_hash);
//		}
//
//		status = add_DEHT(ht,(unsigned char *)curHash, func_buffer_length, (unsigned char *)firstPass, strlen(firstPass));	
//		if (status == DEHT_STATUS_FAIL) {
//			free(seeds);
//			lock_DEHT_files(ht);
//			free_lexicon(lexicon, lexicon_size);
//			free_rule(&rule);
//			exit(1);
//		}
//		fprintf(bigfp, "\n");
//	}
//
//	fclose(bigfp);
//
//	free(seeds);
//	lock_DEHT_files(ht);
//	free_lexicon(lexicon, lexicon_size);
//	free_rule(&rule);
//
//	if (argc != 2)
//	{
//		fprintf(stderr, "Error: Usage crack_rainbow_table <preferences filename>\n");
//		exit(1);
//	}
//
//	/* load .ini file to struct */
//	ini_params = get_params_from_INI_file(argv[1]);
//	/* check params */
//	if (!strcmp(ini_params.HashFunction, "MD5")) {
//		crypt_func = MD5BasicHash;
//		cryptHashSize = MD5_OUTPUT_LENGTH_IN_BYTES;
//	} else if (!strcmp(ini_params.HashFunction, "SHA1")) {
//		crypt_func = SHA1BasicHash;
//		cryptHashSize = SHA1_OUTPUT_LENGTH_IN_BYTES;
//	} else {
//		fprintf(stderr, "Error: Hash %s is not supported\n", argv[1]);
//		exit(1);
//	}
//
//	if (ini_params.ChainLength < 1) {
//		fprintf(stderr, "Error: rainbow_chain_length in %s is %d. It should be positive number\n",
//				argv[1], ini_params.ChainLength);
//		exit(1);
//	}
//
//	if (ini_params.NumOfHashEntries < 1) {
//		fprintf(stderr, "Error: entries_in_hash_table in %s is %d. It should be a positive number\n",
//				argv[1], ini_params.NumOfHashEntries);
//		exit(1);
//	}
//
//	if (ini_params.ElementsInBucket < 1) {
//		fprintf(stderr, "Error: bucket_block_length in %s is %d. It should be a positive number\n",
//				argv[1], ini_params.ElementsInBucket);
//		exit(1);
//	}
//
//	/* create lexicon */
//	lexicon = load_lexicon(ini_params.LexiconName, &lexicon_size);
//	status = create_rule(&rule, ini_params.Rule, lexicon, lexicon_size);
//	if (status == -1) {
//		free_lexicon(lexicon, lexicon_size);
//		exit(1);
//	} 
//
//
//	/* load seed and DEHT */
//	ht = load_DEHT_from_files(ini_params.OutputFilePrefix,cryptHashToTable,cryptHashTo64bit);
//	if (ht == NULL)
//	{
//		free_lexicon(lexicon, lexicon_size);
//		free_rule(&rule);
//		exit(1);
//	}
//	
//	status = read_DEHT_pointers_table(ht);
//	if (status == DEHT_STATUS_FAIL){
//		lock_DEHT_files(ht);
//		free_lexicon(lexicon, lexicon_size);
//		free_rule(&rule);
//		exit(1);
//	}
//
//	seeds = (LONG_INDEX_PROJ*) malloc( ini_params.ChainLength * sizeof(LONG_INDEX_PROJ));
//	if (seeds == NULL){
//		fprintf(stderr, "Error: not enough memory\n");
//		lock_DEHT_files(ht);
//		free_lexicon(lexicon, lexicon_size);
//		free_rule(&rule);
//		exit(1);
//	}
//
//	status = read_DEHT_Seed(ht, seeds, ini_params.ChainLength);
//	if (status == DEHT_STATUS_FAIL)
//	{
//		free(seeds);
//		lock_DEHT_files(ht);
//		free_lexicon(lexicon, lexicon_size);
//		free_rule(&rule);
//		exit(1);
//	}
//
//	/* start main loop */
//	while(quit !=10000 ) {
//		k = pseudo_random_function((unsigned char*)&(quit), sizeof(LONG_INDEX_PROJ), 5461254) % rule.number_of_possible_passwords;
//
//		/* k = seed_random_generator(i, ini_params.MainRandSeed) % rule->number_of_possible_passwords ; */
//		generate_kth_password(k, input+1, rule);
//
//		/* cryptHash(crypt_func, (char *)temp,(unsigned char *) input); */
//		input[0] = '!';
//		quit++;
//		if (status == -1){
//			continue;
//		}
//		if (!strcmp(input, "quit")) {
//			quit = 1;
//			continue;
//		}
//		if (!strcmp(input, "")) {
//			continue;
//		}
//
//		/* if password recieved hash it, else get binary key */
//		if (*input == '!') {
//			cryptHash(crypt_func, input+1, target_key);
//			binary2hexa(target_key, cryptHashSize, hexa_target_key, MAX_HASH_SIZE);
//			status = 0;
//		} else {
//			status = hexa2binary(input, target_key, MAX_HASH_SIZE);
//		}
//
//		/* check command and start cracking */
//		if (status == -1) {
//			fprintf(stderr, "Commands are either hexa, !password or quit.\n");
//			continue;
//		} 
//		else {
//		found = 0;
//		/* start cracking */
//			for (j = ini_params.ChainLength; j >= 0; j--){
//				/* exit for if finished */
//				if (found == 1){
//					break;
//				}
//				/* guess that our password is in j location */
//				memcpy(curHash, target_key, cryptHashSize);
//				/* go down the chain */
//				for (i=j; i<ini_params.ChainLength; i++){
//					k = pseudo_random_function(curHash, cryptHashSize, seeds[i]) % rule.number_of_possible_passwords;
//					generate_kth_password(k,NewPassword, rule);
//					cryptHash(crypt_func, NewPassword, curHash);
//				}
//				/* make querry in deht */
//				multi_length = mult_query_DEHT(ht, curHash, cryptHashSize, multi_data, MAX_INTPUT_SIZE*MAX_RETURN_PW + 1 , multi_point, MAX_RETURN_PW + 1);
//				if (multi_length == DEHT_STATUS_FAIL){
//					free(seeds);
//					lock_DEHT_files(ht);
//					free_lexicon(lexicon, lexicon_size);
//					free_rule(&rule);
//					exit(1);
//				}
//				/* not found - continue to next j */
//				if (multi_length == 0){
//					continue;
//				}
//				
//				/* check multi_data array */
//				for (w=0; w<multi_length; w++){
//					NewPassword_length = multi_point[w + 1] - multi_point[w];
//					if (NewPassword_length > MAX_INTPUT_SIZE){ 
//						continue;
//					}
//					/* try  password */
//					memcpy(NewPassword, multi_point[w], NewPassword_length);
//					NewPassword[NewPassword_length] = '\0';
//
//					/* go j-1 steps down the current chain */
//					for (i = 0; i < j; i++) {
//						cryptHash(crypt_func, NewPassword, curHash);
//						k = pseudo_random_function(curHash, cryptHashSize, seeds[i]) % rule.number_of_possible_passwords;
//						generate_kth_password(k,NewPassword, rule);
//					}
//					
//					/* check this password */
//					cryptHash(crypt_func, NewPassword, curHash);
//					if (memcmp(curHash, target_key, cryptHashSize) == 0) {
//						found = 1; 
//						break;
//					}	
//				}
//			}
//			if (!found) {
//				stat++;
//				fprintf(fp,"%s\n",input);
//			}
//
//		}
//	}
//
//	fclose(fp);
//
//	if (status == DEHT_STATUS_FAIL){
//		free(seeds);
//		lock_DEHT_files(ht);
//		free_lexicon(lexicon, lexicon_size);
//		free_rule(&rule);
//		exit(1);
//	}
//	free(seeds);
//	lock_DEHT_files(ht);
//	free_lexicon(lexicon, lexicon_size);
//	free_rule(&rule);
//	printf("Failed - %d", stat);
//	getchar();
//	return 0;
//}
